/* 模块：array
 * 类型：基础结构
 * 功能：提供静态的一维或多维数组
 * 用法：
 * TODO======================================================================================
 */

#ifndef xpack_utils_array
#define xpack_utils_array
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::utils_array::inc
#include"adapter/random_access.hpp"
#include"define/base_type.hpp"
#include"dumb/disable_copy.hpp"
#include"interface/can_alloc.hpp"
#include"interface/can_callback.hpp"
#include"macro/xdefer.hpp"
#include"macro/xexport.hpp"
#include"macro/xforward.hpp"
#include"macro/xis_nullptr.hpp"
#include"macro/xlikely.hpp"
#include"macro/xnew.hpp"
#include"macro/xstruct.hpp"
#include"memop/cast.hpp"
#include"meta/has_cast.hpp"
#include"meta/has_constructor.hpp"
#include"meta/is_same.hpp"
#include"meta/remove_ref.hpp"
#include"utils/init_item_recursively.hpp"
#include"utils/memory.hpp"
#pragma pop_macro("xuser")

namespace mixc::utils_array{
    template<class type_t, uxx count_v = 0, uxx ... rest_v>
    struct array;

    template<class type_t, uxx ... rest_v>
    struct meta;

    template<class type_t, uxx first_v, uxx count_v, uxx ... rest_v>
    struct meta<type_t, first_v, count_v, rest_v...>{
        using ary   = array<type_t, first_v, count_v, rest_v...>;
        using item  = array<type_t, count_v, rest_v...>;
        using items = item[first_v];
        using base  = inc::random_access<ary, item>;
    };

    template<class type_t, uxx count_v>
    struct meta<type_t, count_v>{
        using ary   = array<type_t, count_v>;
        using item  = type_t;
        using items = item[count_v];
        using base  = inc::random_access<ary, type_t>;
    };

    template<class type_t, uxx count_v = 0, uxx ... rest_v>
    using items     = typename meta<inc::remove_ref<type_t>, count_v, rest_v...>::items;

    template<class type_t, uxx count_v = 0, uxx ... rest_v>
    using base      = typename meta<inc::remove_ref<type_t>, count_v, rest_v...>::base;


    /* 结构：静态数组
     * 参数：
     * - final_t 为接口结构类型
     * - type_t 为第一维度元素类型
     * - count_v 为第一维度元素个数
     * - rest_v 为更高维度元素个数
     */
    template<class type_t, uxx count_v, uxx ... rest_v>
    xstruct(
        xtmpl(array, type_t, count_v, rest_v...),
        xpubb(base<type_t, count_v, rest_v...>),
        xprif_no_mut(m_items, items<type_t, count_v, rest_v...>)
    )
    public:
        using final_t   = the_t;
        using item_t    = inc::remove_ref<decltype(the_t::m_items[0])>;
    public:
        xprops()
            /* 属性：当前维度数组元素的个数 */
            xpubgetx(length, uxx){
                xr{ return count_v; }
            };
        $

        xprops_operator()

    public:
        template<class ... args_t>
        requires(... and inc::has_constructor<item_t, void(args_t &&)>)
        constexpr array(args_t && ... list) : 
            // (item_t &)(args_t &) 和指针的转换类似，会导致不正确的行为
            // m_items { ((item_t &)(args_t &)list)... } {}
            m_items { xforward(list)... } {}

        /* 函数：获取数组元素的首地址 */
        explicit operator item_t *() {
            return m_items;
        }

        /* 函数：获取数组元素的首地址（const 修饰） */
        explicit operator item_t const *() const {
            return m_items;
        }

    private:
        friend base<type_t, count_v, rest_v...>;

        /* 函数：下标随机访问
         * 参数：
         * - index 要访问元素的下标
         * 返回：
         * - 指定索引的元素的引用
         */
        item_t & random_get(uxx index){
            return m_items[index];
        }

        item_t const & random_get(uxx index) const {
            return m_items[index];
        }
    $

    using array_custom_free_invoke = void(*)(struct array_header_info * info, voidp free_mem);

    typedef struct array_header_info{
        uxx need_free           : 1;
        uxx need_destruction    : 1;
        uxx addition_bit        : 1;
        uxx has_custom_free     : 1;
        uxx length              : sizeof(uxx) * 8 - 4;

        template<class item_t>
        inc::memory::size total_bytes_when_item_is(){
            auto size = xsizeof(item_t) * length + sizeof(array_header_info) + (has_custom_free ? sizeof(voidp) : 0);
            return size;
        }

        void custom_free(array_custom_free_invoke invoke){
            // [[no_unique_address]] struct{ ... } custom_free; 方案存在 this 指针定位问题
            *(array_custom_free_invoke *)(this + 1) = invoke;
        }

        void custom_free(array_header_info * info, voidp free_mem){
            (*(array_custom_free_invoke *)(this + 1))(info, free_mem);
        }

    } * array_header_infop;

    inline array_header_info   g_empty_array;

    template<class type_t>
    xstruct(
        xspec(array, type_t),
        xpubb(inc::disable_copy),
        xpubb(inc::random_access<array<type_t>, type_t>),
        xprif(m_tail, array_header_infop),
        xasso(type_t)
    )
        using final_t               = the_t;
        using item_t                = type_t;
        using item_initial_invoke   = inc::icallback<void(item_t * item_ptr)>;
        using item_initial_invokex  = inc::icallback<void(uxx i, item_t * item_ptr)>;
    public:
        xprops()
            xpubget_pubsetx(is_requires_free, bool){
                xr{ return xthe.m_tail->need_free; }
                xw{ xthe.m_tail->need_free = value; }
            };

            xpubget_pubsetx(is_requires_destruction, bool){
                xr{ return xthe.m_tail->need_destruction; }
                xw{ xthe.m_tail->need_destruction = value; }
            };

            xpubget_pubsetx(addition_bit, bool){
                xr{ return xthe.m_tail->addition_bit; }
                xw{ xthe.m_tail->addition_bit = value; }
            };

            xpubgetx(has_custom_free, bool){
                xr{ return xthe.m_tail->has_custom_free; }
            };

            xpubgetx(length, uxx){
                xr{ return xthe.m_tail->length; }
            };
        $

        xprops_operator()

    private:
        static array_header_infop create(uxx length, inc::ialloc<void> alloc, array_custom_free_invoke custom_free){
            using itemp             = item_t *;
            auto    has_custom_free = custom_free != nullptr;
            auto    addition_size   = has_custom_free ? sizeof(array_custom_free_invoke) : 0;
            auto    mem             = alloc(length * sizeof(item_t) + sizeof(array_header_info) + addition_size);
            auto *  info            = array_header_infop(itemp(mem) + length);
            info->length            = length;
            info->need_free         = has_custom_free;
            info->need_destruction  = true;
            info->has_custom_free   = has_custom_free;

            if (has_custom_free){
                info->custom_free(custom_free);
            }
            return info;
        }

        template<class initial_invoke_t>
        static array_header_infop make(
            ::length                    capacity,
            inc::ialloc<void>           alloc,
            initial_invoke_t    const & initial,
            array_custom_free_invoke    custom_free = nullptr
        ){
            using thep_t            = the_t *;
            auto tail               = the_t::create(capacity, alloc, custom_free);
            auto & self             = thep_t(& tail)[0];
            auto begin              = self.item_begin();

            if constexpr (inc::is_same<decltype(nullptr), initial_invoke_t>){
                ; // pass
            }
            else for(uxx i = 0, len = self->length; i < len; i++){
                if constexpr (inc::has_cast<item_initial_invoke, initial_invoke_t>){
                    initial(begin + i);
                }
                else{
                    initial(i, begin + i);
                }
            }
            return tail;
        }
    public:
        constexpr array(decltype(nullptr) = nullptr) : 
            m_tail(& g_empty_array){
        }

        array(array<type_t> && self) :
            m_tail(self.m_tail){
            self.m_tail = & g_empty_array;
        }

        template<class initial_invoke_t>
        requires(
            inc::has_cast<item_initial_invoke , initial_invoke_t> or
            inc::has_cast<item_initial_invokex, initial_invoke_t>
        )
        array(::length capacity, inc::ialloc<void> alloc, initial_invoke_t const & initial, array_custom_free_invoke custom_free = nullptr) : 
            m_tail(the_t::make(capacity, alloc, initial, custom_free)){
        }

        template<class initial_invoke_t>
        requires(
            inc::has_cast<item_initial_invoke , initial_invoke_t> or
            inc::has_cast<item_initial_invokex, initial_invoke_t>
        )
        array(::length capacity, initial_invoke_t const & initial, array_custom_free_invoke custom_free = nullptr) :
            m_tail(the_t::make(capacity, inc::memory::default_alloc<void>, initial, custom_free)) {
            xthe->is_requires_free = true;
        }

        template<class ... args_t>
        requires(inc::has_constructor<item_t, void(args_t && ...)> == true)
        array(::length capacity, inc::ialloc<void> alloc, array_custom_free_invoke custom_free, args_t && ... item_initial_args) :
            // 编译器差异导致必须让 concept 和 bool true 比较才可以被 requires 接受
            m_tail(the_t::make(capacity, alloc, [&](item_t * item_ptr){
                xnew(item_ptr) item_t(xforward(item_initial_args)...);
            }, custom_free)) {
        }

        template<class ... args_t>
        requires(inc::has_constructor<item_t, void(args_t && ...)> == true)
        array(::length capacity, array_custom_free_invoke custom_free, args_t && ... item_initial_args) :
            array(capacity, inc::memory::default_alloc<void>, custom_free, xforward(item_initial_args)...){
            xthe->is_requires_free = true;
        }

        template<class ... args_t>
        requires(inc::has_constructor<item_t, void(args_t && ...)> == true)
        array(::length capacity, inc::ialloc<void> alloc, args_t && ... item_initial_args):
            // 编译器差异导致必须让 concept 和 bool true 比较才可以被 requires 接受
            array(capacity, alloc, nullptr, xforward(item_initial_args)...){
        }

        template<class ... args_t>
        requires(inc::has_constructor<item_t, void(args_t && ...)> == true)
        array(::length capacity, args_t && ... item_initial_args) :
            array(capacity, array_custom_free_invoke{}, xforward(item_initial_args)...){
        }

        template<class ... args_t>
        requires(... and inc::has_constructor<type_t, void(args_t &&)>)
        array(array_custom_free_invoke custom_free, args_t && ... list) : 
            m_tail(the_t::make(::length{ sizeof...(args_t) }, inc::memory::default_alloc<void>, nullptr, custom_free)){
            xthe->is_requires_free = true;
            inc::init_item_recursively(this->item_begin(), xforward(list)...);
        }

        template<class ... args_t>
        requires(... and inc::has_constructor<type_t, void(args_t &&)>)
        array(args_t && ... list): 
            array(array_custom_free_invoke{}, xforward(list)...){
        }

        ~array(){
            *this = nullptr;
        }

    public:
        final_t && hand_over(){
            return (final_t &&)xthe;
        }

        item_t * lend(){
            return this->item_begin();
        }

        final_t & operator=(array<type_t> && self){
            xlikely(this != & self){
                *this       = nullptr;
                xnew(this) the_t((the_t &&)self);
            }
            return xthe;
        }

        /* 函数：获取数组元素的首地址 */
        explicit operator item_t *() {
            return this->item_begin();
        }

        /* 函数：获取数组元素的首地址（const 修饰） */
        explicit operator item_t const *() const {
            return this->item_begin();
        }

        final_t & operator=(decltype(nullptr)){
            if (xthe == nullptr){
                return xthe;
            }

            xdefer{
                m_tail  = nullptr;
            };

            auto begin  = this->item_begin();
            auto length = uxx(xthe->length);

            if (xthe->is_requires_destruction){
                for(uxx i = 0; i < length; i++){
                    begin[i].~item_t();
                }
            }

            if (xthe->is_requires_free){
                if (m_tail->has_custom_free){
                    m_tail->custom_free(m_tail, begin);
                }
                else{
                    inc::memory::free(begin, length * xsizeof(item_t) + xsizeof(array_header_info));
                }
            }
            return xthe;
        }

        xis_nullptr(
            m_tail == & g_empty_array
        )

    protected:
        item_t * item_begin() const {
            return (item_t *)m_tail - m_tail[0].length;
        }

    private:
        friend inc::random_access<the_t, item_t>;

        /* 函数：下标随机访问（const 修饰）
         * 参数：
         * - index 要访问元素的下标
         * 返回：
         * - 指定索引的元素的引用
         */
        item_t & random_get(uxx index) const {
            return this->item_begin()[index];
        }
    $

    template<class first_t, class ... args_t>
    inline array<
        ::mixc::utils_array::inc::remove_ref<first_t>, 1 + sizeof...(args_t)
    > 
    make_array(first_t && first, args_t && ... rest){
        return { xforward(first), xforward(rest)... };
    }
}

namespace mixc::utils_array::origin{
    using mixc::utils_array::array;
    using mixc::utils_array::array_header_info;
    using mixc::utils_array::array_header_infop;
    using mixc::utils_array::make_array;
}

#endif

xexport_space(mixc::utils_array::origin)
